
from typing import Optional, List
from uuid import UUID
from datetime import datetime
from sqlalchemy import select, and_, or_, func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from app.models.record import MedicalRecord, Medication, Instruction
from app.schemas.record import (
    MedicalRecordCreate,
    MedicalRecordUpdate,
    RecordQueryParams
)
from app.core.logger import app_logger


class RecordCRUD:
    """病历 CRUD 操作类"""
    
    @staticmethod
    async def create(
        db: AsyncSession,
        record_data: MedicalRecordCreate,
        medications_data: List[dict] = None,
        instructions_data: List[dict] = None
    ) -> MedicalRecord:
        """
        创建病历记录
        
        Args:
            db: 数据库会话
            record_data: 病历数据
            medications_data: 用药数据列表
            instructions_data: 医嘱数据列表
        """
        try:
            # 创建病历主记录
            db_record = MedicalRecord(**record_data.model_dump())
            db.add(db_record)
            await db.flush()  # 刷新以获取ID
            
            # 创建用药记录
            if medications_data:
                for med_data in medications_data:
                    medication = Medication(
                        record_id=db_record.id,
                        **med_data
                    )
                    db.add(medication)
            
            # 创建医嘱记录
            if instructions_data:
                for inst_data in instructions_data:
                    instruction = Instruction(
                        record_id=db_record.id,
                        **inst_data
                    )
                    db.add(instruction)
            
            await db.commit()
            await db.refresh(db_record)
            
            app_logger.info(f"创建病历成功: ID={db_record.id}, 患者={db_record.patient_name}")
            return db_record
            
        except Exception as e:
            await db.rollback()
            app_logger.error(f"创建病历失败: {e}")
            raise
    
    @staticmethod
    async def get_by_id(db: AsyncSession, record_id: UUID) -> Optional[MedicalRecord]:
        """
        根据ID获取病历
        """
        stmt = (
            select(MedicalRecord)
            .where(and_(
                MedicalRecord.id == record_id,
                MedicalRecord.is_deleted == False
            ))
            .options(
                selectinload(MedicalRecord.medications),
                selectinload(MedicalRecord.instructions),
                selectinload(MedicalRecord.assessments)
            )
        )
        result = await db.execute(stmt)
        return result.scalar_one_or_none()
    
    @staticmethod
    async def get_list(
        db: AsyncSession,
        params: RecordQueryParams,
        page: int = 1,
        page_size: int = 10
    ) -> tuple[List[MedicalRecord], int]:
        """
        获取病历列表（带分页和筛选）
        
        Returns:
            (病历列表, 总数)
        """
        # 构建查询条件
        conditions = [MedicalRecord.is_deleted == False]
        
        if params.patient_name:
            conditions.append(
                MedicalRecord.patient_name.ilike(f"%{params.patient_name}%")
            )
        
        if params.department:
            conditions.append(
                MedicalRecord.department.ilike(f"%{params.department}%")
            )
        
        if params.start_date:
            conditions.append(MedicalRecord.visit_date >= params.start_date)
        
        if params.end_date:
            conditions.append(MedicalRecord.visit_date <= params.end_date)
        
        # 查询总数
        count_stmt = select(func.count()).select_from(MedicalRecord).where(and_(*conditions))
        total_result = await db.execute(count_stmt)
        total = total_result.scalar()
        
        # 查询列表
        stmt = (
            select(MedicalRecord)
            .where(and_(*conditions))
            .order_by(MedicalRecord.created_at.desc())
            .offset((page - 1) * page_size)
            .limit(page_size)
        )
        
        # 如果需要筛选是否已评估
        if params.has_assessment is not None:
            if params.has_assessment:
                stmt = stmt.options(selectinload(MedicalRecord.assessments))
            else:
                stmt = stmt.outerjoin(MedicalRecord.assessments)
        
        result = await db.execute(stmt)
        records = result.scalars().all()
        
        return list(records), total
    
    @staticmethod
    async def update(
        db: AsyncSession,
        record_id: UUID,
        update_data: MedicalRecordUpdate
    ) -> Optional[MedicalRecord]:
        """
        更新病历
        """
        try:
            record = await RecordCRUD.get_by_id(db, record_id)
            if not record:
                return None
            
            # 更新字段
            update_dict = update_data.model_dump(exclude_unset=True)
            for field, value in update_dict.items():
                setattr(record, field, value)
            
            record.updated_at = datetime.now()
            await db.commit()
            await db.refresh(record)
            
            app_logger.info(f"更新病历成功: ID={record_id}")
            return record
            
        except Exception as e:
            await db.rollback()
            app_logger.error(f"更新病历失败: {e}")
            raise
    
    @staticmethod
    async def delete(db: AsyncSession, record_id: UUID) -> bool:
        """
        软删除病历
        """
        try:
            record = await RecordCRUD.get_by_id(db, record_id)
            if not record:
                return False
            
            record.is_deleted = True
            await db.commit()
            
            app_logger.info(f"删除病历成功: ID={record_id}")
            return True
            
        except Exception as e:
            await db.rollback()
            app_logger.error(f"删除病历失败: {e}")
            raise
    
    @staticmethod
    async def get_statistics(db: AsyncSession) -> dict:
        """
        获取统计信息
        """
        # 总病历数
        total_stmt = select(func.count()).select_from(MedicalRecord).where(
            MedicalRecord.is_deleted == False
        )
        total_result = await db.execute(total_stmt)
        total = total_result.scalar()
        
        # 已评估数（有至少一个评估记录）
        assessed_stmt = (
            select(func.count(func.distinct(MedicalRecord.id)))
            .select_from(MedicalRecord)
            .join(MedicalRecord.assessments)
            .where(MedicalRecord.is_deleted == False)
        )
        assessed_result = await db.execute(assessed_stmt)
        assessed = assessed_result.scalar()
        
        return {
            'total_records': total,
            'assessed_records': assessed,
            'pending_records': total - assessed
        }

